#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/types.h>

#include <linux/miscdevice.h>

#include <linux/of.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/of_device.h>

char dev1[100];

struct cdev cdev;

const char *str = NULL;
bool enable = false;
u8 value = 0;
u16 value16 = 0;
u32 value32 = 0;
struct device_node *np = NULL;

//文件打开函数
int hello_open(struct inode *inode, struct file *filp)
{
    filp->private_data = dev1;
    printk("OPEN OK!\n");
    return 0;
}

//文件关闭函数
int hello_release(struct inode *inode, struct file *pfile)
{
    printk("CLOSE OK!\n");
    return 0;
}

//文件读取函数
static ssize_t hello_read( struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    char *register_addr = filp->private_data; /*获取设备的寄存器基地址*/

    /*判断读位置是否有效*/
    if (p >= 5 * sizeof(int))
        return 0;
    if (count > 5 * sizeof(int) - p) /*要读取的字节大于设备的内存空间*/
        count = 5 * sizeof(int) - p;

    /*读数据到用户空间*/
    //如果数据拷贝成功，则返回零；否则，返回没有拷贝成功的数据字节数。
    // To 目标地址，这个地址是用户空间的地址；

    // From 源地址，这个地址是内核空间的地址；
    //  N 将要拷贝的数据的字节数。

    if (copy_to_user(buf, register_addr + p, count))
    {
        ret = -EFAULT;
    }
    else
    {
        *ppos += count;
        ret = count;
    }

    return ret;
}

//文件写入函数
static ssize_t hello_write( struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    int i = 0;
    char *register_addr = filp->private_data; /*获取设备的寄存器地址*/

    /*分析和获取有效的写长度*/
    if (p >= 5 * sizeof(int))
        return 0;

    if (count > 5 * sizeof(int) - p)
        count = 5 * sizeof(int) - p;

    /*从用户空间写入数据*/
    if (copy_from_user(register_addr + p, buf, count))
        ret = -EFAULT;
    else
    {
        *ppos += count;
        ret = count;
    }

    return ret;
}

//文件操作集合
struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
    .read = hello_read,
    .write = hello_write,
};

//在Linux内核中，使用struct miscdevice来表示miscdevice
//初始化struct miscdevice，定义一个misc设备
struct miscdevice miscdev = {
    .minor = MISC_DYNAMIC_MINOR, //动态动态次设备号
    .name = "mis_hello",         //此名称将显示在/dev目录下面
    .fops = &hello_fops,
};

static int foo_remove(struct platform_device *dev)
{
    printk("remove...\n");

    return 0;
}

static int foo_probe(struct platform_device *dev)
{
    int ret = 0;

    misc_register(&miscdev); //注册
    np = dev->dev.of_node;
    // struct device_node *child = NULL;

    // 测试dts读取API
    if (np == NULL)
    {
        printk("of_node is NULL\n");
        return 0;
    }
    return ret;
}


static struct of_device_id foo_of_match[] = {
    {
        .compatible = "ll,jimkent-foo",
    },
    {/* sentinel */}};

static struct platform_driver foo_driver = {
    .driver = {
        .name = "foo",
        .of_match_table = of_match_ptr(foo_of_match),
    },
    .probe = foo_probe,
    .remove = foo_remove,
};

//驱动加载函数
static int __init hello_init(void)
{
    printk("hello_init is NULL\n");
    platform_driver_register(&foo_driver);

    return 0;
}

//驱动卸载函数
static void __exit hello_exit(void)
{
    platform_driver_unregister(&foo_driver);
    misc_deregister(&miscdev); //释放
}

MODULE_LICENSE("GPL");

module_init(hello_init);
module_exit(hello_exit);
